# GPU 渲染基准与界面体验打分 ***Copyright © Quectel Wireless Solutions Co., Ltd. 2026. All rights reserved.*** --- # GPU 渲染基准与界面体验打分(RK3576 / QuecPi M2 Debian) 面向 **Quectel PI M2(RK3576)+ Debian 13 + GNOME Wayland** 开发板的图形性能评测包: 一套 **glmark2 全项跑分**,加上 **桌面动画 / 网页滚动 / 视频播放** 三个真实场景的流畅度打分表。 --- ## 1. 板端实测环境基线 [电子表格] > glmark2 的 6 个 flavor 由包提供:`glmark2`/`glmark2-es2`(X11)、`glmark2-wayland`/`glmark2-es2-wayland`、 > `glmark2-drm`/`glmark2-es2-drm`。**本方案不需要交叉编译 glmark2**,直接用发行版包即可; > 只有当需要 glmark2 上游 master 的新特性时才需要自己用 meson 交叉编译。 --- ### 板载 GPU 与显示架构(实测) RK3576 内置 **ARM Mali-G52 MC3**(Bifrost 架构)。GPU 频率有 **300–900 MHz 共 7 档**,由 `simple_ondemand` 调频——这也是做 GPU 锁频时唯一要关心的节点: ```bash cat /sys/class/devfreq/27800000.gpu/{governor,cur_freq,available_frequencies} ``` **驱动栈是开源的 panfrost + Mesa 25.0.7**,不是 Arm 官方的 Mali blob 驱动。 本板实测暴露出的图形 API 能力(`eglinfo`): [电子表格] > SoC 标称 OpenGL ES 3.2 / Vulkan 1.1 / OpenCL 2.0,但 **本板只暴露到 GLES 3.1、且没有 Vulkan**—— > 这是当前驱动栈的现状而不是硬件限制。所以本方案用 glmark2 的 **GLES 2.0 场景集** 做基准, > 不去碰标称值够不到的那部分。 **关键:本板是"分体式"DRM 架构**,3D GPU 与显示控制器是两个独立的 DRM 设备: [电子表格] 两者靠 Mesa 的 **kmsro** 串联:GPU 渲染到 DRM buffer,再由 rockchip-drm 扫描上屏。 这正是 glmark2 要跑两个口径的原因——**Wayland 口径** 走完整合成链路(GPU → kmsro → 合成器 → VOP, 最贴近真实体验,作为主口径);**DRM 口径** 绕开合成器直接独占 KMS 输出,用来看链路本身损耗多少 (需先停 gdm 让出 DRM master,见 6.3 节)。 **别把隔壁的加速单元当成 GPU**——视频场景能硬解靠的不是它: [电子表格] --- ## 2. 目录结构 整个 `sdk/` 目录是 **自包含的**:push 到开发板任意目录后即可原地执行,**不依赖主机环境** (不需要主机 adb 编排、不需要网络下载)。所有产物都落在 SDK 目录内部: ```plaintext sdk/ # 板端 SDK(push 到板子任意目录即可,例如 /opt/gpu-bench/sdk) ├── install.sh # 【入口1】一键安装:建目录 + 补权限 + 依赖检查 + 环境自检 ├── run-all.sh # 【入口2】一键评测:三场景采集 + glmark2 跑分 + 汇总打分 ├── common.sh # 公共库:会话探测、以桌面用户执行、环境快照 ├── selfcheck.sh # 环境自检(install.sh 会自动调用) ├── glmark2_bench.sh # glmark2 全项跑分(Wayland 主口径 + DRM 对照) ├── frame_monitor.py # kmsgrab 屏幕帧间隔采样器(桌面动画/网页旁路交叉验证) ├── input_inject.py # uinput 虚拟键盘(真实按键触发动画/交互) ├── anim_bench.sh # 场景一:桌面动画 ├── web_bench.sh # 场景二:网页滚动 ├── web/scroll_test.html # 网页场景测试页(页面内 rAF 采集) ├── web/collect_server.py # 结果回传服务(仅监听 127.0.0.1) ├── video_bench.sh # 场景三:视频播放(片源生成 + 硬解/软解) ├── video_probe.py # GStreamer fpsdisplaysink 播放统计 ├── score.py # 汇总打分(生成 results/score_report.md + score_summary.json) ├── score_window.py # 【GTK3】在开发板屏幕上横向弹窗展示最终得分 ├── results/ # 【运行后生成】原始数据 + 打分报告 ├── logs/ # 【运行后生成】每步完整日志 + 环境快照 └── assets/ # 【运行后生成】现场生成的测试片源 ``` 顶层只有本 `README.md` 与 `sdk/`。 --- ## 3. 快速开始 ```bash # 0) 前提:开发板屏幕上已登录 GNOME 桌面(Wayland 口径必需) # 1) 把 SDK 推到板子(在主机上执行一次;目标目录任意,下面以 /opt/gpu-bench 为例) # 注意 A:路径含空格/中文时**必须加引号**,否则 adb 会按空格拆成多个参数 # 注意 B:目标目录已存在时**先删掉**,否则 adb 会嵌套成 /opt/gpu-bench/sdk/sdk 且不覆盖旧文件 adb shell rm -rf /opt/gpu-bench/sdk adb push "<本地路径>/sdk" /opt/gpu-bench/sdk # 2) 进板子,一键安装(建目录 + 权限 + 依赖检查 + 环境自检) adb shell /opt/gpu-bench/sdk/install.sh # 缺依赖时加 --apt 可尝试自动补装 # 3) 一键评测(全程在板子上跑;--quick 是冒烟跑法) adb shell /opt/gpu-bench/sdk/run-all.sh --quick adb shell /opt/gpu-bench/sdk/run-all.sh # 正式:glmark2 3 轮,动画/网页各 10s,视频硬解+软解 adb shell /opt/gpu-bench/sdk/run-all.sh --with-drm # 追加 DRM 直连 KMS 对照(注意第 6.3 节) # 4) 取回结果(在主机上执行) adb pull /opt/gpu-bench/sdk/results ``` > 也可以只在板子上执行——`install.sh` / `run-all.sh` 里没有任何主机侧依赖, > 直接在板端 shell 里 `./install.sh`、`./run-all.sh` 同样可用。 --- ## 4. 命令速查(全部脚本) > - 所有脚本都在 **板端** 执行,并且需要 **root**(要用 `/dev/uinput`、kmsgrab、`systemctl` 等)。 > > - 每个脚本都支持 `-h` / `--help`,直接打印脚本内嵌用法。 > > - 下文统一用 `/opt/gpu-bench/sdk` 作为 SDK 路径,换成你自己的路径即可。 ### 4.1 入口脚本 ```bash # 一键安装:建目录 + 补执行权限 + 依赖检查 + 环境自检(install.sh 内部会调 selfcheck.sh) /opt/gpu-bench/sdk/install.sh /opt/gpu-bench/sdk/install.sh --apt # 依赖缺失时尝试 apt-get install 自动补装 # 环境自检:只读检查,不改动系统;输出 OK/WARN/FAIL 计数 /opt/gpu-bench/sdk/selfcheck.sh # 一键评测:桌面动画 → 网页滚动 → 视频播放 → glmark2 → 汇总打分 /opt/gpu-bench/sdk/run-all.sh # 正式:glmark2 3 轮,动画/网页各 10s,视频硬解+软解 /opt/gpu-bench/sdk/run-all.sh --quick # 冒烟:glmark2 1 轮,动画/网页各 5s,仅常规片源 + 硬解 /opt/gpu-bench/sdk/run-all.sh --runs 5 # glmark2 跑 5 轮 /opt/gpu-bench/sdk/run-all.sh --with-drm # 追加 DRM 直连 KMS 对照口径(会停 gdm,见 6.3 节) /opt/gpu-bench/sdk/run-all.sh --skip-web --skip-gpu # 只跑动画 + 视频 /opt/gpu-bench/sdk/run-all.sh --skip-anim --skip-web --skip-video # 只跑 glmark2 ``` `--skip-*` 可任意组合,用来复用已有结果只补跑其中一项。 ### 4.2 结果窗口(`score_window.py`) GTK3 窗口,在开发板屏幕上 **横向** 并排展示综合分与 4 个维度的得分/等级/权重/关键数据。 `run-all.sh` 跑完会自动弹出(用 `setsid` 脱离会话,不会阻塞脚本退出);也可单独执行: ```bash # 注意:必须切到已登录的桌面用户,且带上 Wayland 环境(等价于 run-all.sh 内部的做法) runuser -u q -- env HOME=/home/q XDG_RUNTIME_DIR=/run/user/1001 \ WAYLAND_DISPLAY=wayland-0 DISPLAY=:0 \ python3 /opt/gpu-bench/sdk/score_window.py \ --summary-json /opt/gpu-bench/sdk/results/score_summary.json ``` > 窗口数据来自 `score.py --json` 产出的 `results/score_summary.json`, > 窗口本身不做任何计算;所以先跑一次 `score.py --json` 才有内容可显示。 --- ## 5. 指标口径定义 [电子表格] > **为什么必须排除"静止间隔"**:GNOME 在画面不变时不重绘,所以一段 5s 采样里如果动画只持续 > 0.5s,把静止时间算进去会得出"几 FPS"的荒谬结果。排除后得到的是动画本身的帧率。 **目标刷新率以实测为准**:桌面动画场景取面板 60Hz;网页滚动场景取页面开始时自测的刷新率。 --- ## 6. 各项怎么测 ### 6.1 桌面动画(`anim_bench.sh`) - **触发真实动画**(不注入假负载): - `overview`:`input_inject.py` 通过 `/dev/uinput` 建虚拟键盘 → 注入 `Super`(概览开/关)。 - `workspace`:先留一个 `gnome-text-editor` 窗口,再注入 `Super+Page_Down/Page_Up`(工作区切换)。 本板各工作区壁纸相同,若工作区里没有窗口,切换时画面完全不变(采样会判定"无动画")。 > - 注意:本板实测绑定的 `Ctrl+Alt+↓/↑` 注入后 **不生效**(画面零变化), > 必须改用同样绑定的 `Super+Page_Down/Page_Up`,切换才会产生真实滑动动画。 - `window`:真实拉起/关闭 `gnome-text-editor`(窗口开合动画)。 - **数据来源**:`frame_monitor.py` 用 ffmpeg `kmsgrab` 以 60fps 从 DRM 主平面旁路采样 (**不需要 DRM master,不打断桌面**),降采样成 64x44 灰度小图后逐帧打时间戳、按平均绝对差 判定"是否为新内容",据此算动画帧率与卡顿分布;间隔 ≥200ms 的静止间隔不计入统计。 - 默认三个子场景:`overview`、`workspace`、`window`,各 10s。 - 精度:采集侧按固定频率轮询,时间戳精度约 ±1 帧(≈16.7ms@60Hz),适合看掉帧/卡顿占比, 不适合做亚帧级分析。 ### 6.2 网页滚动(`web_bench.sh`) - 板上只有 `firefox-esr`(无 chromium、且当前无外网),因此用 **本地 HTML + kiosk 模式**: `web/scroll_test.html` 生成 300 个渐变/圆角/阴影区块的长页面,预热 1.5s 后逐帧 `scrollBy` 滚完整页。 - **主口径**:页面内 `requestAnimationFrame` 时间戳 —— 合成器给页面的帧回调节拍,即滚动时的真实帧率。 - 结果通过 `new Image().src = 'http://127.0.0.1:8799/report?d=``'` 回传(GET 图片请求不受 同源限制,最稳),`web/collect_server.py` 收到即落盘退出。 - 同时用 `frame_monitor.py` 做 **kmsgrab 旁路采样** 做交叉验证(可用 `--no-capture` 关闭)。 ### 6.3 glmark2 全项跑分(`glmark2_bench.sh`) **Wayland 主口径(含合成器,最贴近真实体验)** ```bash adb shell /opt/gpu-bench/sdk/glmark2_bench.sh --backend wayland --runs 3 ``` 在已登录的 GNOME Wayland 会话内以桌面用户身份跑 `glmark2-es2-wayland --fullscreen`, 默认跑全部 17 个场景,结果写 `results/glmark2_wayland_run{1..3}.csv`。 **DRM 对照口径(纯 GPU 上限,不含合成器)** ```bash adb shell /opt/gpu-bench/sdk/glmark2_bench.sh --backend drm --runs 3 ``` DRM flavor 需要 DRM master,脚本会自动 `systemctl stop gdm3` → 跑 `glmark2-es2-drm --fullscreen` → 再 `systemctl start gdm3`(已用 trap 保证异常时也会拉起 gdm)。 > ⚠️ **停 gdm 会终结当前桌面会话**,跑完需要 **在屏幕上重新登录桌面** 才能继续做 GUI 场景 > (板子 `AutomaticLoginEnable=false`)。因此 `run-all.sh` 刻意把 glmark2 排在最后。 > > 若 DRM flavor 报 EGL/GBM 起不来(rockchip-drm 与 panfrost 是分体设备,靠 Mesa kmsro 串联), > 先按 ST 的做法预置好模式再跑: > > ```bash > adb shell "modetest -s 430:1280x800 -d &" > adb shell /opt/gpu-bench/sdk/glmark2_bench.sh --backend drm --runs 1 > ``` > > (430 是本板 DSI-1 的 connector id,可用 `modetest -c` 复核) **跑分偏差控制**:脚本会记录 CPU/GPU governor 与频率、温度、显示模式快照(`logs/env_*.txt`)。 可选 `--lock-gpu` 把 GPU governor 锁到 performance。建议固定:同一分辨率、同一刷新率、 每次跑完等机器降温、3 轮取中位数(`score.py` 自动取中位)。 ```{image} images/image_G9SJbYfnko7sFCx8etjcrjoFn5b.webp :width: 1280px :height: 800px :align: center ``` ### 6.4 视频播放(`video_bench.sh`) - 默认由板端 ffmpeg 现场生成两条可复现片源(已有则复用,也可用 `--video` 指定真实素材): - 普通项 `video_1280x800_30fps_60s.mp4`(testsrc2,30fps) - 压力项 `video_1920x1080_60fps_30s.mp4`(60fps) - 播放链路:`filesrc ! qtdemux ! h264parse ! <解码器> ! fpsdisplaysink video-sink=waylandsink` - 硬解:`mppvideodec`(Rockchip MPP / VPU) - 软解:`avdec_h264`(libav,纯 CPU,用于对比) - 数据来源:`fpsdisplaysink` 的 `frames-rendered` / `frames-dropped` / `average-fps` + `fps-measurements` 信号,直接给出 drop_rate 与平均 FPS。 ```{image} images/image_VfHJb6pkioZq1exu8WGctrypnuc.webp :width: 1280px :height: 800px :align: center ``` --- ## 7. 打分表(`score.py` 自动生成 `results/score_report.md`) [电子表格] ```{image} images/image_KckdbnIzDoisAWxUjuEcGeVSnhe.webp :width: 1280px :height: 800px :align: center ``` **场景流畅度**: ```plaintext 得分 = 10 × [ 0.5 × min(1, 有效FPS / 目标刷新率) + 0.5 × max(0, 1 − jank占比 / 10%) ] ``` **视频播放**: ```plaintext 得分 = 10 × [ 0.5 × (1 − 丢帧率) + 0.5 × min(1, 平均FPS / 片源帧率) ] ``` **综合**:`0.4×glmark2 + 0.2×动画 + 0.2×网页 + 0.2×视频`(缺失项自动按权重归一化)。 > 跑分结束时 `run-all.sh` 会在最后再打印一次精简的 **"最终得分"横幅**(综合分 + 4 个维度 + 等级), > 免得被前面 glmark2 的 17 个场景明细淹没;完整报告仍写入 `results/score_report.md`。 > 也可单独打印:`score.py --results-dir ./results --summary`。 等级对照: [电子表格] > 已按首轮实测校准的阈值(`sdk/score.py` 顶部常量): > `GLMARK2_FULL_SCORE = 100`(官方总分满分线,本板 Wayland 口径实测 **58** → 5.8 分) > 与 `JANK_TOLERANCE = 0.10`(jank 占比容差)。换板子/换分辨率后建议按新基线重设 `GLMARK2_FULL_SCORE`。 --- ## 8. 结果文件对照 [电子表格] > 所有相对路径都相对于 **SDK 目录**(即 `install.sh` 所在目录),产物不会落到 SDK 之外。 --- ## 9. 已知风险与待实测确认项 1. **glmark2-drm 能否直接跑通**:rockchip-drm(card0) 与 panfrost(renderD129) 是分体设备,依赖 Mesa kmsro; 若报 EGL config/GBM 错误,按 6.3 节用 `modetest -s` 预置模式后再跑。 2. **kmsgrab 像素格式(已处理)**:ffmpeg 7.1 的 `hwdownload` 格式协商有缺陷(默认会挑中 `monow` 而报 `Invalid output format`),脚本已改为先用 debug 日志探测主平面 sw_format 再显式指定。若全屏内容 触发 direct scanout 导致主平面格式中途变化(ARGB2101010 → XRGB8888),kmsgrab 会报错退出,脚本会 自动重新探测格式并续采(见 JSON 里的 `format_changes`)。 3. **uinput 注入是否被立即接受**:脚本建完虚拟键盘会等 0.4s 让 libinput 识别;若动画没被触发, 先手动确认一次(`input_inject.py tap leftmeta`)看概览是否弹出。 另注意:工作区切换只有在工作区里 **有窗口** 时才有可见变化(脚本已自动先开一个窗口)。 4. **firefox-esr 首启**:首次用独立 profile 启动较慢(已给 180s 超时);若长时间没收到上报, 用 `--timeout 300` 重跑并观察屏幕。 5. **网页场景的 rAF 帧率可能高于面板刷新率**:GNOME Wayland + firefox-esr 下实测 rAF 可跑到 ~70Hz (说明 rAF 节拍不完全锁 vsync)。打分对帧率部分做了 `min(1, fps/目标)` 封顶,并同时给出 kmsgrab 旁路口径(真实上屏帧)作为交叉验证。 6. **数据可比性**:本方案分数用于同一板子、同一镜像版本下的横向对比(改前后 / 前后版本), 跨平台对比需注明口径差异(是否含合成器、分辨率、刷新率)。 --- ## 10. 参考 - glmark2 官方仓库:[https://github.com/glmark2/glmark2]() - glmark2-wayland 手册(Debian):[https://manpages.debian.org/testing/glmark2-wayland/glmark2-wayland.1.en.html]() - glmark2-drm 手册(Ubuntu):[https://manpages.ubuntu.com/manpages/noble/man1/glmark2-drm.1.html]() - ST Wiki《How to launch glmark2 benchmark》(DRM flavor 需让出 DRM master 的做法): [https://wiki.stmicroelectronics.cn/stm32mpu/index.php?title=How_to_launch_glmark2_benchmark]()